/*******************************************************************************
 * Copyright 2011, 2012 Chris Banes.
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.cloudspace.yunloan.ui.pulltorefresh.base;

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.ListAdapter;
import android.widget.TextView;

import com.cloudspace.yunloan.R;
import com.cloudspace.yunloan.utils.Convert;
import com.cloudspace.yunloan.utils.StringUtil;

public abstract class PullToRefreshBaseAdapterView<T extends AbsListView> extends PullToRefreshBase<T> implements OnScrollListener {

    private OnScrollListener mOnScrollListener;
    private OnItemVisibleListener mOnItemVisibleListener;
    private OnLoadMoreListener mOnLoadMoreListener;

    private View mEmptyView;
    private View mLoadingView;

    private int mCurrentScrollState;
//	private IndicatorLayout mIndicatorIvTop;
//	private IndicatorLayout mIndicatorIvBottom;

    private boolean mScrollEmptyView = true;

    public PullToRefreshBaseAdapterView(Context context) {
        super(context);
        mRefreshableView.setOnScrollListener(this);
    }

    public PullToRefreshBaseAdapterView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mRefreshableView.setOnScrollListener(this);
    }

    public PullToRefreshBaseAdapterView(Context context, Mode mode) {
        super(context, mode);
        mRefreshableView.setOnScrollListener(this);
    }

    public PullToRefreshBaseAdapterView(Context context, Mode mode, AnimationStyle animStyle) {
        super(context, mode, animStyle);
        mRefreshableView.setOnScrollListener(this);
    }

    public final void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
                               final int totalItemCount) {

        if (DEBUG) {
            Log.d(LOG_TAG, "First Visible: " + firstVisibleItem + ". Visible Count: " + visibleItemCount
                    + ". Total Items:" + totalItemCount);
        }
        /**
         * Set whether the Last Item is Visible. lastVisibleItemIndex is a
         * zero-based index, so we minus one totalItemCount to check
         */
        /*if (null != mOnItemVisibleListener) {
			mLastItemVisible = (totalItemCount > 0) && (firstVisibleItem + visibleItemCount >= totalItemCount - 1 );
		}*/

        // Finally call OnScrollListener if we have one
        if (null != mOnScrollListener) {
            mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
        if (null != mOnLoadMoreListener && visibleItemCount < totalItemCount) {
            if (!mIsLoadingMore && mCurrentScrollState != SCROLL_STATE_IDLE) {
                if (firstVisibleItem + visibleItemCount >= totalItemCount) {
                    mIsLoadingMore = true;
                    mOnLoadMoreListener.onLoadMore();
                }
            }
        }
    }

    /**
     * Check that the scrolling has stopped, and that the last item is
     * visible.
     */
    public final void onScrollStateChanged(final AbsListView view, final int state) {
        mCurrentScrollState = state;
        if (state == OnScrollListener.SCROLL_STATE_IDLE && null != mOnItemVisibleListener) {
            boolean mLastItemVisible = (view.getCount() > 0) && (view.getLastVisiblePosition() >= view.getCount() - 1);
            mOnItemVisibleListener.onItemVisible(view, mLastItemVisible);
        }

        if (null != mOnScrollListener) {
            mOnScrollListener.onScrollStateChanged(view, state);
        }
    }

    /**
     * Pass-through method for {@link PullToRefreshBase#getRefreshableView()
     * getRefreshableView()}.
     * {@link AdapterView#setAdapter(Adapter)}
     * setAdapter(adapter)}. This is just for convenience!
     *
     * @param adapter - Adapter to set
     */
    public void setAdapter(ListAdapter adapter) {
        ((AdapterView<ListAdapter>) mRefreshableView).setAdapter(adapter);
    }

    /**
     * Sets the Empty View to be used by the Adapter View.
     * <p/>
     * We need it handle it ourselves so that we can Pull-to-Refresh when the
     * Empty View is shown.
     * <p/>
     * Please note, you do <strong>not</strong> usually need to call this method
     * yourself. Calling setEmptyView on the AdapterView will automatically call
     * this method and set everything up. This includes when the Android
     * Framework automatically sets the Empty View based on it's ID.
     *
     * @param newEmptyView - Empty View to be used
     */
    public final PullToRefreshBaseAdapterView<T> setEmptyView(View newEmptyView) {
        FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();

        // If we already have an Empty View, remove it
        if (null != mEmptyView) {
            refreshableViewWrapper.removeView(mEmptyView);
        }

        if (null != newEmptyView) {
            // New view needs to be clickable so that Android recognizes it as a
            // target for Touch Events
            newEmptyView.setClickable(true);

            ViewParent newEmptyViewParent = newEmptyView.getParent();
            if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) {
                ((ViewGroup) newEmptyViewParent).removeView(newEmptyView);
            }

            // We need to convert any LayoutParams so that it works in our
            // FrameLayout
            FrameLayout.LayoutParams lp = convertEmptyViewLayoutParams(newEmptyView.getLayoutParams());
            if (null != lp) {
                refreshableViewWrapper.addView(newEmptyView, lp);
            } else {
                refreshableViewWrapper.addView(newEmptyView);
            }
        }
        if (mRefreshableView instanceof EmptyViewMethodAccessor) {
            ((EmptyViewMethodAccessor) mRefreshableView).setEmptyViewInternal(newEmptyView);
        } else {
            try {
                mRefreshableView.setEmptyView(newEmptyView);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        mEmptyView = newEmptyView;
        return this;
    }

    private static FrameLayout.LayoutParams convertEmptyViewLayoutParams(ViewGroup.LayoutParams lp) {
        FrameLayout.LayoutParams newLp = null;

        if (null != lp) {
            newLp = new FrameLayout.LayoutParams(lp);

            if (lp instanceof LayoutParams) {
                newLp.gravity = ((LayoutParams) lp).gravity;
            } else {
                newLp.gravity = Gravity.CENTER;
            }

        }
        return newLp;
    }

    public final PullToRefreshBaseAdapterView<T> setEmptyView(String emptyInfo) {
        if (!StringUtil.isEmpty(emptyInfo)) {
            FrameLayout ftv = createEmptyView(emptyInfo);
            setEmptyView(ftv);
        }
        return this;
    }

    public FrameLayout createEmptyView(String emptyInfo) {
        FrameLayout ftv = new FrameLayout(mContext);//为了让textview 和logo居中显示，多增加了一个frameLayout view
        FrameLayout content = new FrameLayout(mContext);
        final Drawable emptyPageIcon = mContext.getResources().getDrawable(R.drawable.emptypage_icon);
        final int iconHeight = emptyPageIcon.getIntrinsicHeight();
        ImageView iv = new ImageView(mContext);
        iv.setScaleType(ScaleType.FIT_XY);
        iv.setImageDrawable(emptyPageIcon);
        FrameLayout.LayoutParams ivLp = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        ivLp.gravity = Gravity.CENTER_HORIZONTAL;
        content.addView(iv, ivLp);
        TextView tv = new TextView(mContext);
        tv.setTextAppearance(mContext, R.style.txt_tips_gray_14px_1);
        tv.setGravity(Gravity.CENTER);
        tv.setText(emptyInfo);
        FrameLayout.LayoutParams tvLp = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        tvLp.topMargin = iconHeight + Convert.getDimensionPixelFromResource(getContext(), R.dimen.dimen_16_dip);
        tvLp.gravity = Gravity.CENTER_HORIZONTAL;
        content.addView(tv, tvLp);

        FrameLayout.LayoutParams contentLp = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        contentLp.bottomMargin = 100;
        if (Build.VERSION.SDK_INT <= 10) {
            content.setPadding(0, 0, 0, 200);
        }
        contentLp.gravity = Gravity.CENTER;
        ftv.addView(content, contentLp);
        return ftv;
    }

    public final void initEmptyView(String str) {
        if (null != str) {
            FrameLayout ftv = new FrameLayout(mContext);
            TextView tv = new TextView(mContext);
            tv.setTextAppearance(mContext, R.style.txt_tips_gray_16px);
            tv.setGravity(Gravity.CENTER);
            tv.setText(str);
            tv.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.emptypage_icon, 0, 0);
            tv.setCompoundDrawablePadding(Convert.getDimensionPixelFromResource(getContext(),
                    R.dimen.dimen_3_dip));
            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            lp.gravity = Gravity.CENTER_VERTICAL;
            ftv.addView(tv, lp);
            setEmptyView(ftv).hideEmptyView();
        }
    }

    public final void showEmptyView() {
        if (null == mEmptyView) {
            return;
        }
        mEmptyView.setVisibility(View.VISIBLE);
    }

    public final View getmEmptyView() {
        if (null != mEmptyView) {
            return mEmptyView;
        }
        return null;
    }

    public final void hideEmptyView() {
        if (null == mEmptyView) {
            return;
        }
        mEmptyView.setVisibility(View.GONE);
    }

    public final void showLoadingView() {
        if (mLoadingView == null && mContext instanceof Activity) {
            mLoadingView = ((Activity) mContext).getLayoutInflater().inflate(R.layout.refresh_loading, null);
        }
        setEmptyView(mLoadingView).showEmptyView();
    }

    /**
     * Pass-through method for {@link PullToRefreshBase#getRefreshableView()
     * getRefreshableView()}.
     * {@link AdapterView#setOnItemClickListener(OnItemClickListener)
     * setOnItemClickListener(listener)}. This is just for convenience!
     *
     * @param listener - OnItemClickListener to use
     */
    public void setOnItemClickListener(OnItemClickListener listener) {
        mRefreshableView.setOnItemClickListener(listener);
    }

    public final void setOnItemVisibleListener(OnItemVisibleListener listener) {
        mOnItemVisibleListener = listener;
    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
        mOnLoadMoreListener = onLoadMoreListener;
    }

    public final void setOnScrollListener(OnScrollListener listener) {
        mOnScrollListener = listener;
    }

    public final void setScrollEmptyView(boolean doScroll) {
        mScrollEmptyView = doScroll;
    }

    @Override
    protected void onPullToRefresh() {
        super.onPullToRefresh();

//		if (getShowIndicatorInternal()) {
//			switch (getCurrentMode()) {
//				case PULL_FROM_END:
//					mIndicatorIvBottom.pullToRefresh();
//					break;
//				case PULL_FROM_START:
//					mIndicatorIvTop.pullToRefresh();
//					break;
//				default:
//					// NO-OP
//					break;
//			}
//		}
    }

    //ˢ��ʱ���� header/footer����
    protected void onRefreshing(boolean doScroll) {
        super.onRefreshing(doScroll);
        // custom action update
    }

    //�ͷ� ˢ��״̬
    @Override
    protected void onReleaseToRefresh() {
        super.onReleaseToRefresh();
        //custom action
    }

    @Override
    protected void onReset() {
        super.onReset();
        // custom action update
    }

    protected boolean isReadyForPullStart() {
        return isFirstItemVisible();
    }

    protected boolean isReadyForPullEnd() {
        return isLastItemVisible();
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (null != mEmptyView && !mScrollEmptyView) {
            mEmptyView.scrollTo(-l, -t);
        }
    }

    @Override
    protected void updateUIForMode() {
        super.updateUIForMode();
    }

    private boolean isFirstItemVisible() {
        final Adapter adapter = mRefreshableView.getAdapter();

        if (null == adapter || adapter.isEmpty()) {
            if (DEBUG) {
                Log.d(LOG_TAG, "isFirstItemVisible. Empty View.");
            }
            return true;

        } else {

            /**
             * This check should really just be:
             * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView
             * internally use a HeaderView which messes the positions up. For
             * now we'll just add one to account for it and rely on the inner
             * condition which checks getTop().
             */
            if (mRefreshableView.getFirstVisiblePosition() <= 1) {
                final View firstVisibleChild = mRefreshableView.getChildAt(0);
                if (firstVisibleChild != null) {
                    return firstVisibleChild.getTop() >= mRefreshableView.getTop();
                }
            }
        }

        return false;
    }

    private boolean isLastItemVisible() {
        final Adapter adapter = mRefreshableView.getAdapter();

        if (null == adapter || adapter.isEmpty()) {
            if (DEBUG) {
                Log.d(LOG_TAG, "isLastItemVisible. Empty View.");
            }
            return true;
        } else {
            final int lastItemPosition = mRefreshableView.getCount() - 1;
            final int lastVisiblePosition = mRefreshableView.getLastVisiblePosition();

            if (DEBUG) {
                Log.d(LOG_TAG, "isLastItemVisible. Last Item Position: " + lastItemPosition + " Last Visible Pos: "
                        + lastVisiblePosition);
            }

            /**
             * This check should really just be: lastVisiblePosition ==
             * lastItemPosition, but PtRListView internally uses a FooterView
             * which messes the positions up. For me we'll just subtract one to
             * account for it and rely on the inner condition which checks
             * getBottom().
             */
            if (lastVisiblePosition >= lastItemPosition - 1) {
                final int childIndex = lastVisiblePosition - mRefreshableView.getFirstVisiblePosition();
                final View lastVisibleChild = mRefreshableView.getChildAt(childIndex);
                if (lastVisibleChild != null) {
                    return lastVisibleChild.getBottom() <= mRefreshableView.getBottom();
                }
            }
        }

        return false;
    }
}
